﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cqrs.Common;

namespace Cqrs.CodeGeneration.CSharp
{
    public partial class IntegrationsTests
    {
        private CSharpGenerator _generatorModel;

        public IntegrationsTests(CSharpGenerator generatorModel)
        {
            _generatorModel = generatorModel;
        }

        public string GetTransitionTourMethods()
        {

            //IEventStore eventStore = new RavenDb(
            //    Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Db"),
            //    new EventPublisher());

            StringBuilder sb = new StringBuilder();

            Dictionary<string, DomainProperty> parameters = new Dictionary<string, DomainProperty>();
            foreach (var commandEvent in _generatorModel.CommandEventGeneratorModels)
            {
                foreach (var property in commandEvent.AffectedProperties)
                {
                    if (!parameters.ContainsKey(property.Name))
                        parameters.Add(property.Name, property);
                }
            }

            string domainParamName = FormatUtils.LowercaseFirst(_generatorModel.DomainName + "Id");

            sb.AppendLine("");

            int tour = 1;
            foreach (var tourSteps in _generatorModel.StateMachine.TransitionTourSequence())
            {
                int version = 0;

                sb.AppendLine("");
                sb.Append(new string(' ', 8));
                sb.AppendLine("[Test]");
                sb.Append(new string(' ', 8));
                sb.AppendLine(string.Format("public void Tour_{0}()", tour++));
                sb.Append(new string(' ', 8));
                sb.AppendLine("{");

                sb.Append(new string(' ', 12));
                sb.AppendLine(
                    string.Format("Guid {0} = Guid.NewGuid();",
                        domainParamName));

                foreach (var affectedProperty in parameters)
                {
                    sb.Append(new string(' ', 12));
                    sb.AppendLine(string.Format("{0} {1} = {2};",
                        affectedProperty.Value.Type,
                        FormatUtils.LowercaseFirst(affectedProperty.Value.Name),
                        RandomParamData(affectedProperty.Value.Type)));
                }

                foreach (var step in tourSteps)
                {
                    var affectedProps = _generatorModel.CommandEventGeneratorModels
                                            .Where(p => p.DomainMethod == step.Command).FirstOrDefault();

                    string randomData = "";
                    if (affectedProps != null)
                    {
                        foreach (var prop in affectedProps.AffectedProperties)
                        {
                            randomData += FormatUtils.LowercaseFirst(prop.Name);
                            randomData += ", ";
                        }
                    }

                    sb.Append(new string(' ', 12));
                    sb.AppendLine(
                        string.Format(
                        "_commandHandler.Submit(new {0}({1}{2}{3}));",
                                step.Command,
                                domainParamName + ", ",
                                randomData,
                                version++));
                    sb.Append(new string(' ', 12));
                    sb.AppendLine(string.Format(@"AssertState({0}, ""{1}"");", domainParamName, step.ToState));

                }
                sb.Append(new string(' ', 8));
                sb.AppendLine("}");
            }

            return sb.ToString();
        }

        private string RandomParamData(string paramType)
        {
            switch (paramType.ToLower())
            {
                case "byte":
                    return "";
                case "bool":
                    return "false";
                case "char":
                    return "'x'";
                case "datetime":
                    return "DateTime.Now";
                case "decimal":
                    return "1";
                case "double":
                    return "1";
                case "float":
                    return "1";
                case "guid":
                    return "Guid.NewGuid()";
                case "int":
                    return "1";
                case "long":
                    return "1"; ;
                case "object":
                    return "new object";
                case "sbyte":
                    return "1";
                case "short":
                    return "1";
                case "string":
                    return string.Format(@"""{0}""", GenerateRandomString(12));
                case "uint":
                    return "1";
                case "ulong":
                    return "1";
                case "ushort":
                    return "1";
                default:
                    return string.Format("new {0}()", paramType);
            }
        }

        // http://stackoverflow.com/questions/1122483/c-sharp-random-string-generator
        private static readonly Random _random = new Random();
        private const string _letters = "abcdefghijklmnopqrstuvwxyz";
        private string GenerateRandomString(int maxNumberOfLetters)
        {
            char[] buffer = new char[maxNumberOfLetters];

            for (int i = 0; i < maxNumberOfLetters; i++)
            {
                buffer[i] = _letters[_random.Next(_letters.Length)];
            }
            return new string(buffer);
        }
    }
}
